package classesPERT;

import graph.Edge;
import graph.GenericGraph;
import graph.Node;

import java.util.ArrayList;

public class PERTNetwerk {

	public PERTNetwerk() {
	}

	public ArrayList<Node> topologicalSorting(GenericGraph graph) {
		// http://en.wikipedia.org/wiki/Topological_sorting
		// starters
		ArrayList<Node> startingNodes = calculateStartingNodes(graph);
		// sorted list
		ArrayList<Node> sorted = new ArrayList<Node>();
		// while there are still vertix
		while (!startingNodes.isEmpty()) {
			// remove it from the list
			Node removed = startingNodes.remove(0);
			// add it to the sorted
			sorted.add(removed);
			// get all neighbours
			ArrayList<Node> neighbours = removed.getNextNeighbours();
			// for every neighbour remove the connection
			// and add it to the startNodes list IF it has no incoming
			// connections
			for (Node node : neighbours) {
				removed.removeEdgeTo(node);
				node.removeEdgeFrom(removed);
				if (node.getIncoming().size() == 0) {
					startingNodes.add(node);
				}
			}
		}
		return sorted;
	}

	private ArrayList<Node> calculateStartingNodes(GenericGraph graph) {
		ArrayList<Node> startingNodes = new ArrayList<Node>();
		for (Node node : graph.getNodes()) {
			if (node.getIncoming().size() == 0) {
				startingNodes.add(node);
			}
		}
		return startingNodes;
	}

	public void calculateEarliest(GenericGraph graph, ArrayList<Node> sortedList) {
		// loop langs de sorted list
		for (Node node : sortedList) {
			// halen coresponderende node op
			Node workingNode = graph.getNodeByName(node.getName());
			// wanneer de node geen incoming heeft is het een startpunt dus
			// earliest = 0
			if (workingNode.checkIncoming()) {
				workingNode.setEarliest(0);
			}
			// zo niet dan gaan we bereken hoeveel het moet zijn
			// namelijk de laagste kost van alle incomingEdges + incomingNode

			else {
				for (Edge edge : workingNode.getIncoming()) {
					int newCost = edge.getCost()
							+ edge.getBeginning().getEarliest();
					if (newCost > workingNode.getEarliest()
							|| workingNode.getEarliest() == -1) {
						workingNode.setEarliest(newCost);
					}
				}
			}
		}
	}

	public void calculateLatest(GenericGraph graph, ArrayList<Node> sortedList) {
		for (int i = 0; i < sortedList.size(); i++) {
			// achterste eerst beginnen
			Node sortedNode = sortedList.get(sortedList.size() - 1 - i);
			Node workingNode = graph.getNodeByName(sortedNode.getName());

			// als de node geen inkomende lijnen heeft
			if (workingNode.getOutgoing().size() < 1) {
				workingNode.setLatest(workingNode.getEarliest());
			} else {
				for (Edge edge : workingNode.getOutgoing()) {
					int latestTime = edge.getEnd().getLatest() - edge.getCost();
					if ((workingNode.getLatest() == -1)
							| latestTime < workingNode.getLatest()) {
						workingNode.setLatest(latestTime);
					}
				}
			}
		}
	}
}
